package com.xl.intercepter;

import cn.hutool.core.util.StrUtil;
import com.xl.constants.Constants;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.UUID;

/**
 * 进行websocket连接之间进行校验，校验通过才可以连接websocket服务器
 * 建立连接的时候会先进入到 beforeHandshake , afterhandshake, 然后再进入到presend
 */
@Component
public class WebsocketIntercepter implements HandshakeInterceptor, ChannelInterceptor {
    //连接websocket之前进行校验
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        //检查亲请求头中是否包含鉴权信息
        if (request instanceof ServletServerHttpRequest) {
            HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
            String authorizatiom = req.getHeader("Sec-WebSocket-Protocol");
            if (StrUtil.isBlank(authorizatiom)) {
                System.out.println("未知请求连接socket服务器,authorization:" + authorizatiom);
                return false;
            }
            //解析token的内容，将消息放到session里面 token格式：auth-userID
            //随机生成一个uuid
            String uuid = UUID.randomUUID().toString().replace("-", "");
            String[] split = authorizatiom.split("-");
            attributes.put(Constants.USER_UUID_KEY, uuid);
            attributes.put(Constants.USER_INFO_KEY, split[1]);
            return true;
        } else {
            return false;
        }
    }

    //连接websocket之后进行数据处理
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        if (request instanceof ServletServerHttpRequest) {
            HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
            HttpServletResponse httpResponse = ((ServletServerHttpResponse) response).getServletResponse();
            if (StrUtil.isNotEmpty(req.getHeader("Sec-WebSocket-Protocol"))) {
                httpResponse.addHeader("Sec-WebSocket-Protocol", req.getHeader("Sec-WebSocket-Protocol"));
            }
        }
    }

    /**
     * 此处可拦截通道信息
     * 连接websocket，断开连接，订阅topic，取消订阅topic ，通过应用前缀（MessageMapping方法）发送消息，都会进入到这拦截器里面，
     *
     * @param message
     * @param channel
     * @return
     */
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        //连接websocket的时候拿到用户信息
        //取出用户携带的参数 用户连接时把用户信息放在了请求头里面，然后再beforehandshake中
        //又把用户信息放到了attribute里面了
        //如果StompCommand是connect表示已经连接成功了，可以记录一下用户的信息
        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            Object raw = message.getHeaders().get("simpSessionAttributes");
            System.out.println(raw);
            if (raw instanceof Map) {
                Object uuid = ((Map<?, ?>) raw).get(Constants.USER_UUID_KEY);
                Object userInfo = ((Map<?, ?>) raw).get(Constants.USER_INFO_KEY);
                System.out.println(uuid);
                System.out.println(userInfo);
                // 设置当前访问的认证用户
                //accessor.setUser(new UserPrincipal(((ArrayList) name).get(0).toString()));

            }
        }
        System.out.println(message);
        String msg = message.getPayload().toString();
        System.out.println(msg);
        return message;
    }
}
